home *** CD-ROM | disk | FTP | other *** search
- --------!-ALGORITHMS------------------------
- Some algorithms used for encoding images etc...
- --- TIFF PackBits algorithm
-
- Abstract
-
- This document describes a simple compression scheme for bilevel scanned
- and paint type files.
-
-
- Motivation
-
- The TIFF specification defines a number of compression schemes.
- Compression type 1 is really no compression, other than basic pixel
- packing. Compression type 2, based on CCITT 1D compression, is powerful,
- but not trivial to implement. Compression type 5 is typically very
- effective for most bilevel images, as well as many deeper images such as
- palette color and grayscale images, but is also not trivial to
- implement. PackBits is a simple but often effective alternative.
-
-
- Description
-
- Several good schemes were already in use in various settings. We
- somewhat arbitrarily picked the Macintosh PackBits scheme. It is byte
- oriented, so there is no problem with word alignment. And it has a good
- worst case behavior (at most 1 extra byte for every 128 input bytes).
- For Macintosh users, there are toolbox utilities PackBits and UnPackBits
- that will do the work for you, but it is easy to implement your own
- routines.
-
- A pseudo code fragment to unpack might look like this:
-
- Loop until you get the number of unpacked bytes you are
- expecting:
- Read the next source byte into n.
- If n is between 0 and 127 inclusive, copy the next n+1 bytes
- literally.
- Else if n is between -127 and -1 inclusive, copy the next
- byte -n+1 times.
- Else if n is 128, noop.
- Endloop
-
- In the inverse routine, it's best to encode a 2-byte repeat run as a
- replicate run except when preceded and followed by a literal run, in
- which case it's best to merge the three into one literal run. Always
- encode 3-byte repeats as replicate runs.
-
- So that's the algorithm. Here are some other rules:
-
- o Each row must be packed separately. Do not compress across
- row boundaries.
-
- o The number of uncompressed bytes per row is defined to be
- (ImageWidth + 7) / 8. If the uncompressed bitmap is required to
- have an even number of bytes per row, decompress into word-
- aligned buffers.
- o If a run is larger than 128 bytes, simply encode the
- remainder of the run as one or more additional replicate runs.
-
- When PackBits data is uncompressed, the result should be interpreted as
- per compression type 1 (no compression).
-
- --- TIFF LZW Compression
-
- Abstract
-
- This document describes an adaptive compression scheme for raster
- images.
-
- Reference
-
- Terry A. Welch, "A Technique for High Performance Data Compression",
- IEEE Computer, vol. 17 no. 6 (June 1984). Describes the basic Lempel-Ziv
- & Welch (LZW) algorithm. The author's goal in the article is to describe
- a hardware-based compressor that could be built into a disk controller
- or database engine, and used on all types of data. There is no specific
- discussion of raster images. We intend to give sufficient information in
- this Appendix so that the article is not required reading.
-
- Requirements
-
- A compression scheme with the following characteristics should work well
- in a desktop publishing environment:
-
- o Must work well for images of any bit depth, including images
- deeper than 8 bits per sample.
- o Must be effective: an average compression ratio of at least
- 2:1 or better. And it must have a reasonable worst-case
- behavior, in case something really strange is thrown at it.
- o Should not depend on small variations between pixels.
- Palette color images tend to contain abrupt changes in index
- values, due to common patterning and dithering techniques. These
- abrupt changes do tend to be repetitive, however, and the scheme
- should make use of this fact.
- o For images generated by paint programs, the scheme should
- not depend on a particular pattern width. 8x8 pixel patterns are
- common now, but we should not assume that this situation will not
- change.
- o Must be fast. It should not take more than 5 seconds to
- decompress a 100K byte grayscale image on a 68020- or 386-based
- computer. Compression can be slower, but probably not by more
- than a factor of 2 or 3.
- o The level of implementation complexity must be reasonable.
- We would like something that can be implemented in no more than a
- couple of weeks by a competent software engineer with some
- experience in image processing. The compiled code for
- compression and decompression combined should be no more than
- about 10K.
- o Does not require floating point software or hardware.
-
-
- The following sections describe an algorithm based on the "LZW"
- (Lempel-Ziv & Welch) technique that meets the above requirements.
- In addition meeting our requirements, LZW has the following
- characteristics:
-
- o LZW is fully reversible. All information is preserved. But
- if noise or information is removed from an image, perhaps by
- smoothing or zeroing some low-order bitplanes, LZW compresses
- images to a smaller size. Thus, 5-bit, 6-bit, or 7-bit data
- masquerading as 8-bit data compresses better than true 8-bit
- data. Smooth images also compress better than noisy images, and
- simple images compress better than complex images.
- o On a 68082- or 386-based computer, LZW software can be
- written to compress at between 30K and 80K bytes per second,
- depending on image characteristics. LZW decompression speeds are
- typically about 50K bytes per second.
- o LZW works well on bilevel images, too. It always beats
- PackBits, and generally ties CCITT 1D (Modified Huffman)
- compression, on our test images. Tying CCITT 1D is impressive in
- that LZW seems to be considerably faster than CCITT 1D, at least
- in our implementation.
- o Our implementation is written in C, and compiles to about 2K
- bytes of object code each for the compressor and decompressor.
- o One of the nice things about LZW is that it is used quite
- widely in other applications such as archival programs, and is
- therefore more of a known quantity.
-
-
- The Algorithm
-
- Each strip is compressed independently. We strongly recommend that
- RowsPerStrip be chosen such that each strip contains about 8K bytes
- before compression. We want to keep the strips small enough so that the
- compressed and uncompressed versions of the strip can be kept entirely
- in memory even on small machines, but large enough to maintain nearly
- optimal compression ratios.
-
- The LZW algorithm is based on a translation table, or string table, that
- maps strings of input characters into codes. The TIFF implementation
- uses variable-length codes, with a maximum code length of 12 bits. This
- string table is different for every strip, and, remarkably, does not
- need to be kept around for the decompressor. The trick is to make the
- decompressor automatically build the same table as is built when
- compressing the data. We use a C-like pseudocode to describe the coding
- scheme:
-
- InitializeStringTable();
- WriteCode(ClearCode);
- Omega = the empty string;
- for each character in the strip {
- K = GetNextCharacter();
- if Omega+K is in the string table {
- Omega = Omega+K; /* string concatenation */
- } else {
- WriteCode (CodeFromString(Omega));
- AddTableEntry(Omega+K);
- Omega = K;
- }
- } /* end of for loop */
- WriteCode (CodeFromString(Omega));
- WriteCode (EndOfInformation);
-
- That's it. The scheme is simple, although it is fairly challenging to
- implement efficiently. But we need a few explanations before we go on to
- decompression.
-
- The "characters" that make up the LZW strings are bytes containing TIFF
- uncompressed (Compression=1) image data, in our implementation. For
- example, if BitsPerSample is 4, each 8-bit LZW character will contain
- two 4-bit pixels. If BitsPerSample is 16, each 16-bit pixel will span
- two 8-bit LZW characters.
-
- (It is also possible to implement a version of LZW where the LZW
- character depth equals BitsPerSample, as was described by Draft 2 of
- Revision 5.0. But there is a major problem with this approach. If
- BitsPerSample is greater than 11, we can not use 12-bit-maximum codes,
- so that the resulting LZW table is unacceptably large. Fortunately, due
- to the adaptive nature of LZW, we do not pay a significant compression
- ratio penalty for combining several pixels into one byte before
- compressing. For example, our 4-bit sample images compressed about 3
- percent worse, and our 1-bit images compressed about 5 percent better.
- And it is easier to write an LZW compressor that always uses the same
- character depth than it is to write one which can handle varying
- depths.)
-
- We can now describe some of the routine and variable references in our
- pseudocode:
-
- InitializeStringTable() initializes the string table to contain all
- possible single-character strings. There are 256 of them, numbered 0
- through 255, since our characters are bytes.
-
- WriteCode() writes a code to the output stream. The first code written
- is a Clear code, which is defined to be code #256.
-
- Omega is our "prefix string."
-
- GetNextCharacter() retrieves the next character value from the input
- stream. This will be number between 0 and 255, since our characters are
- bytes.
-
- The "+" signs indicate string concatenation.
-
- AddTableEntry() adds a table entry. (InitializeStringTable() has already
- put 256 entries in our table. Each entry consists of a single-character
- string, and its associated code value, which is, in our application,
- identical to the character itself. That is, the 0th entry in our table
- consists of the string <0>, with corresponding code value of <0>, the
- 1st entry in the table consists of the string <1>, with corresponding
- code value of <1>, ..., and the 255th entry in our table consists of the
- string <255>, with corresponding code value of <255>.) So the first
- entry that we add to our string table will be at position 256, right?
- Well, not quite, since we will reserve code #256 for a special "Clear"
- code, and code #257 for a special "EndOfInformation" code that we will
- write out at the end of the strip. So the first multiple-character entry
- added to the string table will be at position 258.
-
- Let's try an example. Suppose we have input data that looks like:
-
- Pixel 0: <7>
- Pixel 1: <7>
- Pixel 2: <7>
- Pixel 3: <8>
- Pixel 4: <8>
- Pixel 5: <7>
- Pixel 6: <7>
- Pixel 7: <6>
- Pixel 8: <6>
-
- First, we read Pixel 0 into K. OmegaK is then simply <7>, since Omega is
- the empty string at this point. Is the string <7> already in the string
- table? Of course, since all single character strings were put in the
- table by InitializeStringTable(). So set Omega equal to <7>, and go to
- the top of the loop.
-
- Read Pixel 1 into K. Does OmegaK (<7><7>) exist in the string table? No,
- so we get to do some real work. We write the code associated with Omega
- to output (write <7> to output), and add OmegaK (<7><7>) to the table as
- entry 258. Store K (<7>) into Omega. Note that although we have added
- the string consisting of Pixel 0 and Pixel 1 to the table, we "re-use"
- Pixel 1 as the beginning of the next string.
-
- Back at the top of the loop. We read Pixel 2 into K. Does OmegaK
- (<7><7>) exist in the string table? Yes, the entry we just added, entry
- 258, contains exactly <7><7>. So we just add K onto the end of Omega, so
- that Omega is now <7><7>.
-
- Back at the top of the loop. We read Pixel 3 into K. Does OmegaK
- (<7><7><8>) exist in the string table? No, so write the code associated
- with Omega (<258>) to output, and add OmegaK to the table as entry 259.
- Store K (<8>) into Omega.
-
- Back at the top of the loop. We read Pixel 4 into K. Does OmegaK
- (<8><8>) exist in the string table? No, so write the code associated
- with Omega (<8>) to output, and add OmegaK to the table as entry 260.
- Store K (<8>) into Omega.
-
- Continuing, we get the following results:
-
- After reading: We write to output: And add table entry:
- Pixel 0
- Pixel 1 <7> 258: <7><7>
- Pixel 2
- Pixel 3 <258> 259: <7><7><8>
- Pixel 4 <8> 260: <8><8>
- Pixel 5 <8> 261: <8><7>
- Pixel 6
- Pixel 7 <258> 262: <7><7><6>
- Pixel 8 <6> 263: <6><6>
-
- WriteCode() also requires some explanation. The output code stream,
- <7><258><8><8><258><6>... in our example, should be written using as few
- bits as possible. When we are just starting out, we can use 9-bit codes,
- since our new string table entries are greater than 255 but less than
- 512. But when we add table entry 512, we must switch to 10-bit codes.
- Likewise, we switch to 11-bit codes at 1024, and 12-bit codes at 2048.
- We will somewhat arbitrarily limit ourselves to 12-bit codes, so that
- our table can have at most 4096 entries. If we push it any farther,
- tables tend to get too large.
-
- What happens if we run out of room in our string table? This is where
- the afore-mentioned Clear code comes in. As soon as we use entry 4094,
- we write out a (12-bit) Clear code. (If we wait any dworder to write the
- Clear code, the decompressor might try to interpret the Clear code as a
- 13-bit code.) At this point, the compressor re-initializes the string
- table and starts writing out 9-bit codes again.
-
- Note that whenever you write a code and add a table entry, Omega is not
- left empty. It contains exactly one character. Be careful not to lose it
- when you write an end-of-table Clear code. You can either write it out
- as a 12-bit code before writing the Clear code, in which case you will
- want to do it right after adding table entry 4093, or after the clear
- code as a 9-bit code. Decompression gives the same result in either
- case.
-
- To make things a little simpler for the decompressor, we will require
- that each strip begins with a Clear code, and ends with an
- EndOfInformation code.
-
- Every LZW-compressed strip must begin on a byte boundary. It need not
- begin on a word boundary. LZW compression codes are stored into bytes in
- high-to-low-order fashion, i.e., FillOrder is assumed to be 1. The
- compressed codes are written as bytes, not words, so that the compressed
- data will be identical regardless of whether it is an "II" or "MM" file.
-
- Note that the LZW string table is a continuously updated history of the
- strings that have been encountered in the data. It thus reflects the
- characteristics of the data, providing a high degree of adaptability.
-
-
- LZW Decoding
-
- The procedure for decompression is a little more complicated, but
- still not too bad:
-
- while ((Code = GetNextCode()) != EoiCode) {
- if (Code == ClearCode) {
- InitializeTable();
- Code = GetNextCode();
- if (Code == EoiCode)
- break;
- WriteString(StringFromCode(Code));
- OldCode = Code;
- } /* end of ClearCode case */
-
- else {
- if (IsInTable(Code)) {
- WriteString(StringFromCode(Code));
- AddStringToTable(StringFromCode(OldCode)+
- FirstChar(StringFromCode(Code)));
- OldCode = Code;
- } else {
- OutString = StringFromCode(OldCode) +
- FirstChar(StringFromCode(OldCode));
- WriteString(OutString);
- AddStringToTable(OutString);
- OldCode = Code;
- }
- } /* end of not-ClearCode case */
- } /* end of while loop */
-
- The function GetNextCode() retrieves the next code from the LZW- coded
- data. It must keep track of bit boundaries. It knows that the first code
- that it gets will be a 9-bit code. We add a table entry each time we get
- a code, so GetNextCode() must switch over to 10-bit codes as soon as
- string #511 is stored into the table.
-
- The function StringFromCode() gets the string associated with a
- particular code from the string table.
-
- The function AddStringToTable() adds a string to the string table. The
- "+" sign joining the two parts of the argument to AddStringToTable
- indicate string concatenation.
-
- StringFromCode() looks up the string associated with a given code.
-
- WriteString() adds a string to the output stream.
-
-
- When SamplesPerPixel Is Greater Than 1
-
- We have so far described the compression scheme as if SamplesPerPixel
- were always 1, as will be be the case with palette color and grayscale
- images. But what do we do with RGB image data?
-
- Tests on our sample images indicate that the LZW compression ratio is
- nearly identical regardless of whether PlanarConfiguration=1 or
- PlanarConfiguration=2, for RGB images. So use whichever configuration
- you prefer, and simply compress the bytes in the strip.
-
- It is worth cautioning that compression ratios on our test RGB images
- were disappointing low: somewhere between 1.1 to 1 and 1.5 to 1,
- depending on the image. Vendors are urged to do what they can to remove
- as much noise from their images as possible. Preliminary tests indicate
- that significantly better compression ratios are possible with less
- noisy images. Even something as simple as zeroing out one or two
- least-significant bitplanes may be quite effective, with little or no
- perceptible image degradation.
-
-
- Implementation
-
- The exact structure of the string table and the method used to determine
- if a string is already in the table are probably the most significant
- design decisions in the implementation of a LZW compressor and
- decompressor. Hashing has been suggested as a useful technique for the
- compressor. We have chosen a tree based approach, with good results. The
- decompressor is actually more straightforward, as well as faster, since
- no search is involved - strings can be accessed directly by code value.
-
-
- Performance
-
- Many people do not realize that the performance of any compression
- scheme depends greatly on the type of data to which it is applied. A
- scheme that works well on one data set may do poorly on the next.
-
- But since we do not want to burden the world with too many compression
- schemes, an adaptive scheme such as LZW that performs quite well on a
- wide range of images is very desirable. LZW may not always give optimal
- compression ratios, but its adaptive nature and relative simplicity seem
- to make it a good choice.
-
- Experiments thus far indicate that we can expect compression ratios of
- between 1.5 and 3.0 to 1 from LZW, with no loss of data, on continuous
- tone grayscale scanned images. If we zero the least significant one or
- two bitplanes of 8-bit data, higher ratios can be achieved. These
- bitplanes often consist chiefly of noise, in which case little or no
- loss in image quality will be perceived. Palette color images created in
- a paint program generally compress much better than continuous tone
- scanned images, since paint images tend to be more repetitive. It is not
- unusual to achieve compression ratios of 10 to 1 or better when using
- LZW on palette color paint images.
-
- By way of comparison, PackBits, used in TIFF for black and white bilevel
- images, does not do well on color paint images, much less continuous
- tone grayscale and color images. 1.2 to 1 seemed to be about average for
- 4-bit images, and 8-bit images are worse.
-
- It has been suggested that the CCITT 1D scheme could be used for
- continuous tone images, by compressing each bitplane separately. No
- doubt some compression could be achieved, but it seems unlikely that a
- scheme based on a fixed table that is optimized for word black runs
- separated by dworder white runs would be a very good choice on any of
- the bitplanes. It would do quite well on the high-order bitplanes (but
- so would a simpler scheme like PackBits), and would do quite poorly on
- the low-order bitplanes. We believe that the compression ratios would
- generally not be very impressive, and the process would in addition be
- quite slow. Splitting the pixels into bitplanes and putting them back
- together is somewhat expensive, and the coding is also fairly slow when
- implemented in software.
-
- Another approach that has been suggested uses uses a 2D differencing
- step following by coding the differences using a fixed table of
- variable-length codes. This type of scheme works quite well on many
- 8-bit grayscale images, and is probably simpler to implement than LZW.
- But it has a number of disadvantages when used on a wide variety of
- images. First, it is not adaptive. This makes a big difference when
- compressing data such as 8-bit images that have been "sharpened" using
- one of the standard techniques. Such images tend to get larger instead
- of smaller when compressed. Another disadvantage of these schemes is
- that they do not do well with a wide range of bit depths. The built-in
- code table has to be optimized for a particular bit depth in order to be
- effective.
-
- Finally, we should mention "lossy" compression schemes. Extensive
- research has been done in the area of lossy, or non-
- information-preserving image compression. These techniques generally
- yield much higher compression ratios than can be achieved by
- fully-reversible, information-preserving image compression techniques
- such as PackBits and LZW. Some disadvantages: many of the lossy
- techniques are so computationally expensive that hardware assists are
- required. Others are so complicated that most microcomputer software
- vendors could not afford either the expense of implementation or the
- increase in application object code size. Yet others sacrifice enough
- image quality to make them unsuitable for publishing use.
-
- In spite of these difficulties, we believe that there will one day be a
- standardized lossy compression scheme for full color images that will be
- usable for publishing applications on microcomputers. An International
- Standards Organization group, ISO/IEC/JTC1/SC2/WG8, in cooperation with
- CCITT Study Group VIII, is hard at work on a scheme that might be
- appropriate. We expect that a future revision of TIFF will incorporate
- this scheme once it is finalized, if it turns out to satisfy the needs
- of desktop publishers and others in the microcomputer community. This
- will augment, not replace, LZW as an approved TIFF compression scheme.
- LZW will very likely remain the scheme of choice for Palette color
- images, and perhaps 4-bit grayscale images, and may well overtake CCITT
- 1D and PackBits for bilevel images.
-
-
- Future LZW Extensions
-
- Some images compress better using LZW coding if they are first subjected
- to a process wherein each pixel value is replaced by the difference
- between the pixel and the preceding pixel. Performing this differencing
- in two dimensions helps some images even more. However, many images do
- not compress better with this extra preprocessing, and for a significant
- number of images, the compression ratio is actually worse. We are
- therefore not making differencing an integral part of the TIFF LZW
- compression scheme.
-
- However, it is possible that a "prediction" stage like differencing may
- exist which is effective over a broad range of images. If such a scheme
- is found, it may be incorporated in the next major TIFF revision. If so,
- a new value will be defined for the new "Predictor" TIFF tag. Therefore,
- all TIFF readers that read LZW files must pay attention to the Predictor
- tag. If it is 1, which is the default case, LZW decompression may
- proceed safely. If it is not 1, and the reader does not recognize the
- specified prediction scheme, the reader should give up.
-
-
- Acknowledgements
-
- The original LZW reference has already been given. The use of ClearCode
- as a technique to handle overflow was borrowed from the compression
- scheme used by the Graphics Interchange Format (GIF), a
- small-color-paint-image-file format used by CompuServe that also is an
- adaptation of the LZW technique. Joff Morgan and Eric Robinson of Aldus
- were each instrumental in their own way in getting LZW off the ground.
-
- The TIFF predictor algorithm
-
- The idea is to make use of the fact that many continuous tone images
- rarely vary much in pixel value from one pixel to the next. In such
- images, if we replace the pixel values by differences between
- consecutive pixels, many of the differences should be 0, plus or minus
- 1, and so on. This reduces the apparent information content, and thus
- allows LZW to encode the data more compactly.
-
- Assuming 8-bit grayscale pixels for the moment, a basic C implementation
- might look something like this:
-
- char image[ ][ ];
- int row, col;
-
- /* take horizontal differences:
- */
- for (row = 0; row < nrows; row++)
- for (col = ncols - 1; col >= 1; col--)
- image[row][col] -= image[row][col-1];
-
- If we don't have 8-bit samples, we need to work a little harder, so that
- we can make better use of the architecture of most CPUs. Suppose we have
- 4-bit samples, packed two to a byte, in normal TIFF uncompressed (i.e.,
- Compression=1) fashion. In order to find differences, we want to first
- expand each 4-bit sample into an 8-bit byte, so that we have one sample
- per byte, low-order justified. We then perform the above horizontal
- differencing. Once the differencing has been completed, we then repack
- the 4- bit differences two to a byte, in normal TIFF uncompressed
- fashion.
-
- If the samples are greater than 8 bits deep, expanding the samples into
- 16-bit words instead of 8-bit bytes seems like the best way to perform
- the subtraction on most computers.
-
- Note that we have not lost any data up to this point, nor will we lose
- any data later on. It might at first seem that our differencing might
- turn 8-bit samples into 9-bit differences, 4- bit samples into 5-bit
- differences, and so on. But it turns out that we can completely ignore
- the "overflow" bits caused by subtracting a larger number from a smaller
- number and still reverse the process without error. Normal twos
- complement arithmetic does just what we want. Try an example by hand if
- you need more convincing.
-
- Up to this point we have implicitly assumed that we are compressing
- bilevel or grayscale images. An additional consideration arises in the
- case of color images.
-
- If PlanarConfiguration is 2, there is no problem. Differencing proceeds
- the same way as it would for grayscale data.
-
- If PlanarConfiguration is 1, however, things get a little trickier. If
- we didnt do anything special, we would be subtracting red sample values
- from green sample values, green sample values from blue sample values,
- and blue sample values from red sample values, which would not give the
- LZW coding stage much redundancy to work with. So we will do our
- horizontal differences with an offset of SamplesPerPixel (3, in the RGB
- case). In other words, we will subtract red from red, green from green,
- and blue from blue. The LZW coding stage is identical to the
- SamplesPerPixel=1 case. We require that BitsPerSample be the same for
- all 3 samples.
-
-
- Results and guidelines
-
- LZW without differencing works well for 1-bit images, 4-bit grayscale
- images, and synthetic color images. But natural 24-bit color images and
- some 8-bit grayscale images do much better with differencing. For
- example, our 24-bit natural test images hardly compressed at all using
- "plain" LZW: the average compression ratio was 1.04 to 1. The average
- compression ratio with horizontal differencing was 1.40 to 1. (A
- compression ratio of 1.40 to 1 means that if the uncompressed image is
- 1.40MB in size, the compressed version is 1MB in size.)
-
- Although the combination of LZW coding with horizontal differencing does
- not result in any loss of data, it may be worthwhile in some situations
- to give up some information by removing as much noise as possible from
- the image data before doing the differencing, especially with 8-bit
- samples. The simplest way to get rid of noise is to mask off one or two
- low- order bits of each 8-bit sample. On our 24-bit test images, LZW
- with horizontal differencing yielded an average compression ratio of 1.4
- to 1. When the low-order bit was masked from each sample, the
- compression ratio climbed to 1.8 to 1; the compression ratio was 2.4 to
- 1 when masking two bits, and 3.4 to 1 when masking three bits. Of
- course, the more you mask, the more you risk losing useful information
- adword with the noise. We encourage you to experiment to find the best
- compromise for your device. For some applications it may be useful to
- let the user make the final decision.
-
- Interestingly, most of our RGB images compressed slightly better using
- PlanarConfiguration=1. One might think that compressing the red, green,
- and blue difference planes separately (PlanarConfiguration=2) might give
- better compression results than mixing the differences together before
- compressing (PlanarConfiguration=1), but this does not appear to be the
- case.
-
- Incidentally, we tried taking both horizontal and vertical differences,
- but the extra complexity of two-dimensional differencing did not appear
- to pay off for most of our test images. About one third of the images
- compressed slightly better with two-dimensional differencing, about one
- third compressed slightly worse, and the rest were about the same.
-
- --- BMP RLE_8 compression
-
- The BMP can be compressed in two modes, absolute mode and RLE mode. Both
- modes can occur anywhere in a single bitmap.
-
- The RLE mode is a simple RLE mechanism, the first byte contains the
- count, the second byte the pixel to be replicatet. If the count byte is
- 0, the second byte is a special, like EOL or delta.
-
- In absolute mode, the second byte contains the number of bytes to be
- copied litteraly. Each absolute run must be word-aligned that means you
- will may have to add an aditional padding byte which is not included in
- the count. After an absolute run, RLE compression continues.
-
- Second byte Meaning
-
- 0 End of line
- 1 End of bitmap
- 2 Delta. The next two bytes are the horizontal
- and vertical offsets from the current position
- to the next pixel.
- 3-255 Switch to absolute mode
-
- --- BMP RLE_4 compression
-
- RLE_4 compression knows the two modes of the RLE_8 compression, absolute
- and RLE. In the RLE mode, the first byte contains the count of pixels to
- draw, the second byte contains in its two nibbles the indices off the
- pixel colors, the higher 4 bits are the left pixel, the lower 4 bits are
- the right pixel. Note that two-color runs are possible to encode with
- RLE_4 through this.
-
- --- Protracker sample compression / decompression
-
- Get the number of sample bytes to process. Call this SamplesLeft.
-
- Set Delta counter to 0.
-
- DO
- Get a byte from the buffer.
- Store the byte in Temp.
- Subtract the Delta counter from the byte.
- Store it in the buffer.
- Move the Temp byte into the Delta Counter
- Decrement SamplesLeft.
- WHILE(SamplesLeft <> 0)
-
- The technique for conversion back to the raw data is:
-
- Get the number of sample bytes to process.
- Call this SamplesLeft.
-
- Set Delta counter to 0.
-
- DO
- Get a byte from the buffer.
- Add onto the byte the Delta Counter.
- Store the byte in Delta Counter.
- Store the byte in Temp.
- Decrement SamplesLeft.
- WHILE(SamplesLeft <> 0)
-
-